import java.util.logging.Handler;
import java.util.logging.LogRecord;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JMenu;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JOptionPane;
import javax.swing.tree.DefaultTreeModel;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.Toolkit;
import java.awt.event.*;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Point;
import java.text.DateFormat;
import java.util.Calendar;
import javax.swing.JMenuItem;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JDialog;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.net.InetAddress;

/**
 * Contains all methods to extend Webster
 * with a GUI.
 *
 * @author Marlon Etheredge
 * @author <a href="mailto:m.etheredge@gmail.com">m.etheredge@gmail.com</a>
 * @author <a href="http://www.foxage.nl/">http://www.foxage.nl</a>
 */
public class WebsterGUI extends JFrame implements ActionListener, ItemListener {

    /** Servertree. */
    private JTree tree;

    /** TextArea for output of Webservers. */
    private JTextArea textArea;

    /** Checkbox menu item for verbose option in menu. */
    private JCheckBoxMenuItem verboseMenuItem;

    /** Menu item for starting of server in menu. */
    private JMenuItem startServerMenuItem;

    /** Menu item for removing a server in menu. */
    private JMenuItem removeServerMenuItem;

    /** Menu item for settings the htdocs path in menu. */
    private JMenuItem htdocsPathMenuItem;

    /** Menu item for exit in menu. */
    private JMenuItem exitMenuItem;

    /** Root of the servertree. */
    private DefaultMutableTreeNode top;

    /**
     * Constructs a new WebsterGUI instance,
     * and thus builds a new WebsterGUI.
     */
    public WebsterGUI() {
        super();
        
        this.setDefaultSettings();
        this.setLookNFeel();
        this.addTrayIcon();
        this.addTextArea();
        this.addStatusLabel();
        this.addMenuBar();
        this.setSize(800, 600);
        
        this.startWebster();

        this.addServerTree();
        this.pack();
    }
    
    /**
     * Graphically start an instance of Webster.
     */
    private void startWebster() {
        final DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL);
        final Calendar calendar = Calendar.getInstance();
        
        Handler loggerHandler = new Handler() {
            public void publish(LogRecord logRecord) {
                calendar.setTimeInMillis(logRecord.getMillis());
                WebsterGUI.this.addLine(formatter.format(calendar.getTime()) + " " + logRecord.getMessage());
            }
            
            public void flush() {
            }
            
            public void close() {
            }
        };
        
        Webster.setLoggerHandler(loggerHandler);
        Webster.initializeWebster();
    }
    
    /**
     *Sets the look 'n feel of the GUI.
     */
    private void setLookNFeel() {
        try {
            // Set System L&F
            UIManager.setLookAndFeel(
            UIManager.getSystemLookAndFeelClassName());
        } 
        catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * Adds the menubar to this WebsterGUI.
     */
    private void addMenuBar() {
       JMenuBar menuBar = new JMenuBar();
       
       JMenu menu = new JMenu("Webster");
       menuBar.add(menu);
       
       startServerMenuItem = new JMenuItem("Start server");
       startServerMenuItem.setMnemonic(KeyEvent.VK_S);
       startServerMenuItem.addActionListener(this);
       menu.add(startServerMenuItem);

       removeServerMenuItem = new JMenuItem("Remove server");
       removeServerMenuItem.setMnemonic(KeyEvent.VK_R);
       removeServerMenuItem.addActionListener(this);
       menu.add(removeServerMenuItem);

       htdocsPathMenuItem = new JMenuItem("Set htdocs path");
       htdocsPathMenuItem.setMnemonic(KeyEvent.VK_H);
       htdocsPathMenuItem.addActionListener(this);
       menu.add(htdocsPathMenuItem);

       verboseMenuItem = new JCheckBoxMenuItem("Verbose");
       verboseMenuItem.setSelected(Webster.verbose);
       verboseMenuItem.setMnemonic(KeyEvent.VK_V);
       verboseMenuItem.addItemListener(this);
       menu.add(verboseMenuItem);
       
       menu.addSeparator();
       
       exitMenuItem = new JMenuItem("Exit");
       exitMenuItem.setMnemonic(KeyEvent.VK_E);
       exitMenuItem.addActionListener(this);
       menu.add(exitMenuItem);
       
       this.setJMenuBar(menuBar);
    }

    /**
     * Sets the default settings of the GUI.
     */
    private void setDefaultSettings() {
        this.setVisible(true);
        this.setTitle("Webster v0.0.1");
        this.setDefaultCloseOperation(HIDE_ON_CLOSE);
    }
    
    /**
     * Adds the textpane to this WebsterGUI.
     */
    private void addTextArea() {
        this.textArea = new JTextArea();
        this.textArea.setEditable(false);
        JScrollPane scrollpane = new JScrollPane(this.textArea,
                                                 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                                                 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        getContentPane().add(scrollpane);

    }
    
    /**
     * Adds the statuslabel to this WebsterGUI.
     */
    private void addStatusLabel() {
        JLabel statusLabel = new JLabel("Webster v0.0.1");
        
        this.getContentPane().add(statusLabel, BorderLayout.PAGE_END);
    }
    
    /**
     * Adds the servertree to this WebsterGUI.
     */
    private void addServerTree() {
        top = new DefaultMutableTreeNode("Running Webster Servers");
        tree = new JTree(top);
        JScrollPane treeView = new JScrollPane(tree);

        this.getContentPane().add(treeView, BorderLayout.LINE_END);

        this.updateServerTree();
    }

    /**
     * Update the servertree with current servers.
     */
    public void updateServerTree() {
        this.top.removeAllChildren();

        for(Webserver webserver : Webster.getWebservers()) {
            DefaultMutableTreeNode addressNode = new DefaultMutableTreeNode(webserver, true);
            this.top.add(new DefaultMutableTreeNode(addressNode));
        }

        ((DefaultTreeModel)this.tree.getModel()).nodeStructureChanged(this.top);
    }
    
    /**
     * Adds the trayicon to this WebsterGUI.
     */
    private void addTrayIcon() {
        final TrayIcon trayIcon;
        
        if (SystemTray.isSupported()) {
            SystemTray tray = SystemTray.getSystemTray();
            Image image = Toolkit.getDefaultToolkit().getImage("webster.gif");
        
            ActionListener exitListener = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    System.exit(0);
                }
            };
                    
            PopupMenu popup = new PopupMenu();
            MenuItem defaultItem = new MenuItem("Exit");
            defaultItem.addActionListener(exitListener);
            popup.add(defaultItem);
        
            trayIcon = new TrayIcon(image, "Webster", popup);
        
            ActionListener actionListener = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    WebsterGUI.this.setVisible(true);
                }
            };
                    
            trayIcon.setImageAutoSize(true);
            trayIcon.addActionListener(actionListener);
        
            try {
                tray.add(trayIcon);
            } catch (AWTException e) {
                System.err.println("TrayIcon could not be added.");
            }
        
        } else {
            System.out.println("Tray icon is not supported");
        } 
    }
    
    /**
     * Actionperformed method for ActionListener in GUI.
     */
    public void actionPerformed(ActionEvent event) {
        JMenuItem source = (JMenuItem)(event.getSource());
        
        if(source == exitMenuItem)
            System.exit(0);
        else if(source == startServerMenuItem)
            new CreateServerDialog(this);
        else if(source == removeServerMenuItem)
            new RemoveServerDialog(this);
        else if(source == htdocsPathMenuItem) {
            String path = JOptionPane.showInputDialog(this,
                                "Path to htdocs (absolute or relative):",
                                "Set htdocs path",
                                JOptionPane.QUESTION_MESSAGE);

            FileHandler.setHtdocs(path);
        }
    }

    /**
     * Itemstatechanged method for ItemListener in GUI.
     */
    public void itemStateChanged(ItemEvent event) {
        JMenuItem source = (JMenuItem)(event.getSource());
        
        if(source == verboseMenuItem)
            Webster.verbose = true;
    }

    /**
     * Entry point.
     */
    public static void main(String[] args) {
        WebsterGUI gui = new WebsterGUI();
    }
    
    /**
     * Adds a line to the TextArea.
     *
     * @param line Line to add.
     */
    public void addLine(String line) {
        this.textArea.setText(this.textArea.getText() + line + "\n");
    }
    
}